<template>
  <div>
    <el-dialog
      v-model="dialogVisible"
      :title="opentionType + '样式'"
      class="style-add-or-update-dialog"
      width="1400px"
      :before-close="closeDialog"
      draggable
    >
      <div class="style-preset-conterner">
        <el-form
          ref="ruleFormRef"
          :model="stylePresetForm"
          :inline="true"
          label-width="auto"
          class="style-preset-form"
        >
          <el-form-item label="工作空间 :">
            <el-select
              v-model="stylePresetForm.workspace"
              filterable
              clearable
              :disabled="opentionType == '编辑'"
              style="width: 150px"
              placeholder="请选择工作空间"
              @change="workspaceChangeHandler"
            >
              <el-option
                v-for="workspaceItem in workspaceList"
                :key="workspaceItem.name"
                :label="workspaceItem.name"
                :value="workspaceItem.name"
              />
            </el-select>
          </el-form-item>
          <el-form-item
            label="样式名称"
            prop="name"
            :rules="{
              required: true,
              message: '样式名称不能为空',
              trigger: 'blur',
            }"
          >
            <el-input
              v-model="stylePresetForm.name"
              style="width: 150px"
              placeholder="请输入样式名称"
            />
          </el-form-item>
        </el-form>
      </div>

      <el-tabs type="border-card" class="slyle-editor-conterner">
        <el-tab-pane label="图形化配置">
          <el-table
            :data="styleRulesTable"
            class="rule-table"
            @selection-change="handleRuleTableSelectionChange"
          >
            <el-table-column type="selection" width="55" />

            <el-table-column label="符号" width="80">
              <template #default="scope">
                <div style="position: relative; width: 46px; height: 30px">
                  <mapSymbolConterner
                    v-if="dialogVisible"
                    :geo-rule="scope.row"
                    @singleclick="showSymbolPickerDialog(scope.row, scope.$index)"
                  >
                  </mapSymbolConterner>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="名称">
              <template #default="scope">
                <el-input v-model="scope.row.name" />
              </template>
            </el-table-column>
            <el-table-column label="过滤条件">
              <template #default="scope">
                <el-input
                  v-model="scope.row.tempFilter"
                  @change="updateCurrentRowFilter(scope.row)"
                >
                </el-input>
              </template>
            </el-table-column>
            <el-table-column label="最小比例尺" width="180">
              <template #default="scope">
                <el-input-number v-model="scope.row.scaleDenominator.min" type="number" />
              </template>
            </el-table-column>
            <el-table-column label="最大比例尺" width="180">
              <template #default="scope">
                <el-input-number v-model="scope.row.scaleDenominator.max" type="number" />
              </template>
            </el-table-column>
          </el-table>
          <el-row class="rule-operations">
            <el-button size="small" text :icon="Plus" @click="addRuleHandler">添加</el-button>
            <el-button
              size="small"
              text
              :icon="Minus"
              :disabled="multipleSelectionRulesTable.length == 0"
              @click="removeRuleHandler"
              >移除</el-button
            >
          </el-row>
        </el-tab-pane>
        <el-tab-pane label="专业模式">
          <codemirror
            v-model="stylePresetForm.sldFileText"
            placeholder="Code goes here..."
            :style="{ height: '400px' }"
            :autofocus="true"
            :indent-with-tab="true"
            :tab-size="2"
            :extensions="extensions"
            @ready="codemirrorHandleReady"
            @change="console.log('change', $event)"
            @focus="console.log('focus', $event)"
            @blur="console.log('blur', $event)"
          />
        </el-tab-pane>
      </el-tabs>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="closeDialog">取消</el-button>
          <el-button type="primary" @click="addOrUpdate">确认</el-button>
        </span>
      </template>
    </el-dialog>
    <symbolPickerDialog
      ref="symbolPickerDialogRef"
      @update-rule-symbolizers="updateCurrentRule"
    ></symbolPickerDialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, watch, toRef, onBeforeMount, shallowRef } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'
import { Plus, Minus } from '@element-plus/icons-vue'
import SLDParser from 'geostyler-sld-parser'
import CQLParser from 'geostyler-cql-parser'
import vkbeautify from 'vkbeautify' // 美化xml组件
import { Codemirror } from 'vue-codemirror'
import { xml as codemirrorXml } from '@codemirror/lang-xml'
import { oneDark } from '@codemirror/theme-one-dark'
import type { Style as GeoStyleType, Rule as GeoRule, Filter as GeoFilter } from 'geostyler-style'
import useWorkspaceModal from '@/composables/useWorkspace'
import mapSymbolConterner from './symbolPreview/mapSymbolConterner.vue'
import symbolPickerDialog from './symbolPickerDialog.vue'
import type { IStyle } from 'geoserver-helper/interface'
import { restHelperInstance } from '@/composables/useGeoHelper'

const cqlParser = new CQLParser()
interface propsType {
  visible: boolean
  styleInfo?: IStyle.StyleDetailInfo
  type: string
}
const props = withDefaults(defineProps<propsType>(), {
  visible: false,
  type: '新增',
})
const dialogVisible = toRef(props, 'visible')
const orignEditData = toRef(props, 'styleInfo')
const opentionType = toRef(props, 'type')
interface addOrUpdateStyleEmit {
  (e: 'updateStyles'): void
  (e: 'update:visible', v: boolean): void
}

const emit = defineEmits<addOrUpdateStyleEmit>()
interface symbolPickerDialogExpose {
  openDialog: () => void
  setOrignEditData: (geoRule: GeoRule) => void
}
const symbolPickerDialogRef = ref<symbolPickerDialogExpose | undefined>()

// 工作空间hook
const workspaceModal = useWorkspaceModal()
const workspaceList = workspaceModal.workspaceList

// 表单ref
const ruleFormRef = ref<FormInstance>()

// codemirror 扩展
const extensions = [codemirrorXml(), oneDark]
const codeView = shallowRef()
const codemirrorHandleReady = (payload: { view: any }) => {
  codeView.value = payload.view
}

const parser = new SLDParser()

const mapVisible = ref(false)

interface extendGeoRule extends GeoRule {
  tempFilter: string
}

const defaultStyleRule: extendGeoRule = {
  name: 'default',
  filter: undefined,
  tempFilter: '',
  scaleDenominator: {
    min: undefined,
    max: undefined,
  },
  symbolizers: [
    {
      kind: 'Fill', // 规则类型
      color: '#ff0000',
      fillOpacity: 1,
      outlineColor: '',
      outlineWidth: 0,
      outlineOpacity: 1,
      outlineDasharray: [],
    },
  ],
}
const currentRuleIndex = ref<number>()

// 样式Rules
const styleRulesTable = ref<extendGeoRule[]>([{ ...defaultStyleRule }])
const multipleSelectionRulesTable = ref<extendGeoRule[]>([])
interface StyleAddOrUpdateForm {
  name: string
  sldFileText: string
  workspace: string
}
// 默认表单预设
const defaultPresetForm: StyleAddOrUpdateForm = {
  name: '',
  sldFileText: '',
  workspace: '',
}
// 表单预设
let stylePresetForm = reactive<StyleAddOrUpdateForm>(JSON.parse(JSON.stringify(defaultPresetForm)))

// 当前 GeoStyle
let currentGeoStyle = reactive<GeoStyleType>({
  name: stylePresetForm.name,
  rules: [],
})

/**
 * @description: 工作空间下拉改变事件
 * @param {string} selectedValue 选中的工作空间
 */
const workspaceChangeHandler = (selectedValue: string) => {
  stylePresetForm.workspace = selectedValue
}

/**
 * @description: 打开符号选择器
 * @param {*} geoRule
 * @return {*}
 */
const showSymbolPickerDialog = (geoRule: GeoRule, ruleIndex: number) => {
  currentRuleIndex.value = ruleIndex
  symbolPickerDialogRef.value?.setOrignEditData(geoRule)
  symbolPickerDialogRef.value?.openDialog()
}
/**
 * @description: 更新当前规则样式
 * @param {*} geoRule
 * @return {*}
 */
const updateCurrentRule = (geoRule: GeoRule) => {
  const tempGeoRule = JSON.parse(JSON.stringify(geoRule))
  styleRulesTable.value[currentRuleIndex.value as number] = tempGeoRule
  // styleRulesTable.value.splice(currentRuleIndex.value as number, 1, geoRule)
}

/**
 * @description: 打开当前弹窗
 * @param {*} opentionTypeParam
 * @return {*}
 */
const openDialog = (opentionTypeParam?: string) => {
  if (opentionTypeParam) {
    opentionType.value = opentionTypeParam
  }
  dialogVisible.value = true
  if (opentionTypeParam === '新增') {
    setTimeout(() => {
      // 地图需要在界面显示之后进行渲染
      mapVisible.value = true
    }, 100)
  }
  setTimeout(() => {
    // 地图需要在界面显示之后进行渲染
    mapVisible.value = true
  }, 300)
}

const handleRuleTableSelectionChange = (val: any[]) => {
  multipleSelectionRulesTable.value = val
}
/**
 * @description: 添加样式规则
 * @return {void}
 */
const addRuleHandler = () => {
  styleRulesTable.value.push({ ...defaultStyleRule } as any)
}

/**
 * @description: 更新当前行的过滤器
 * @param {extendGeoRule} geoRule
 * @return {*}
 */
const updateCurrentRowFilter = (geoRule: extendGeoRule) => {
  const cqlParseredResult = cqlParser.read(geoRule.tempFilter)
  if (cqlParseredResult) {
    geoRule.filter = cqlParser.read(geoRule.tempFilter) as GeoFilter
  }
}
/**
 * @description: 移除选中样式规则
 * @return {void}
 */
const removeRuleHandler = () => {
  if (multipleSelectionRulesTable.value.length > 0) {
    ElMessageBox.confirm('确认移除选中的规则么?', '', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
      .then(() => {
        multipleSelectionRulesTable.value.forEach((singleItem) => {
          const currentIndex = styleRulesTable.value.findIndex((findItem) => {
            return findItem == singleItem
          })
          if (currentIndex >= 0) {
            styleRulesTable.value.splice(currentIndex, 1)
          }
        })
      })
      .catch(() => {})
  }
}
const initCurrentStyle = () => {
  if (orignEditData.value?.name) {
    stylePresetForm.name = orignEditData.value.name + ''
    let workspaceName = ''
    if (orignEditData.value.workspace) {
      workspaceName = orignEditData.value.workspace.name
    }
    stylePresetForm.workspace = workspaceName
    restHelperInstance
      .getSldStyleApi(stylePresetForm.name, stylePresetForm.workspace)
      .then((sldRes) => {
        if (sldRes) {
          stylePresetForm.sldFileText = sldRes
          const formatSldString = sldRes.replace(/UserLayer/g, 'NamedLayer')
          parser.readStyle(formatSldString).then((geoStyle) => {
            // currentGeoStyle = geoStyle.output as GeoStyleType
            currentGeoStyle = geoStyle.output as any
            //@ts-ignore
            styleRulesTable.value = currentGeoStyle.rules.map((mapItem) => {
              mapItem.scaleDenominator = Object.assign(
                {
                  min: undefined,
                  max: undefined,
                },
                mapItem.scaleDenominator,
              )
              //@ts-ignore
              const cqlFilterString = cqlParser.write(mapItem.filter as GeoFilter) || ''
              return { ...mapItem, tempFilter: cqlFilterString } as extendGeoRule
            })
          })
        }
      })
  }
}
watch(
  () => orignEditData.value,
  () => {
    initCurrentStyle()
  },
  {
    immediate: true,
  },
)
watch(
  () => styleRulesTable.value,
  () => {
    currentGeoStyle.rules = styleRulesTable.value as any
    parser.writeStyle(currentGeoStyle as any).then((sldStyle) => {
      let readyToFormatXml = sldStyle.output
      stylePresetForm.sldFileText = vkbeautify.xml(readyToFormatXml) as string
    })
  },
  {
    deep: true,
  },
)
/**
 * @description: 关闭当前弹窗
 * @return {*}
 */
const closeDialog = () => {
  stylePresetForm = reactive<StyleAddOrUpdateForm>(JSON.parse(JSON.stringify(defaultPresetForm)))
  emit('update:visible', false)
  // dialogVisible.value = false
}

/**
 * @description: 添加或更新样式
 * @return {*}
 */
const addOrUpdate = () => {
  ruleFormRef.value?.validate((valid, fields) => {
    if (valid) {
      if (opentionType.value == '新增') {
        restHelperInstance
          .addStyleApi(stylePresetForm.sldFileText, stylePresetForm.name, stylePresetForm.workspace)
          .then(() => {
            ElMessage({
              type: 'success',
              message: '添加成功',
            })
            closeDialog()
            emit('updateStyles')
          })
          .catch(() => {
            ElMessage({
              type: 'error',
              message: '添加失败！',
            })
          })
      } else if (opentionType.value == '编辑') {
        restHelperInstance
          .updateStyleApi(
            stylePresetForm.sldFileText,
            orignEditData.value!.name,
            stylePresetForm.name,
            stylePresetForm.workspace,
          )
          .then(() => {
            ElMessage({
              type: 'success',
              message: '更新成功',
            })
            closeDialog()
            emit('updateStyles')
          })
          .catch(() => {
            ElMessage({
              type: 'error',
              message: '更新失败！',
            })
          })
      }
    }
  })
}
onBeforeMount(() => {
  // 此处执行一次后确保 workspaceList 有值
  workspaceModal.getWorkspaceList()
})
defineExpose({ openDialog })
</script>
<style lang="scss">
.style-add-or-update-dialog {
  .el-dialog__body {
    padding: 20px;
    padding-top: 5px;
    .style-preset-conterner {
      display: flex;
      align-items: center;
      width: 100%;
      height: 40px;

      // background-color: #ffde66;
      // border-bottom: 3px solid #ffc800;
      .style-preset-form {
        width: 100%;
        padding: 0 10px;
        .el-form-item {
          margin-right: 15px;
          margin-bottom: 0;
          :deep(.el-form-item__content) {
            .el-form-item__error {
              z-index: 3;
            }
          }
        }
      }
    }
    .slyle-editor-conterner {
      width: 100%;
      min-height: 500px;
      .rule-table {
        width: 100%;
      }
      .rule-operations {
        display: flex;
        align-items: center;
        width: 100%;
        height: 50px;
      }
    }
  }
  .el-dialog__footer {
    padding: 20px;
    text-align: right;
  }
}
</style>
